package com.gzsxy.esjy.gateway.config;


import com.alibaba.fastjson.JSON;
import com.gzsxy.esjy.common.base.util.FileUtils;
import com.gzsxy.esjy.gateway.dto.Route;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;

import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Component;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;


import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

/**
 * @author xiaolong
 * @version 1.0
 * @description: 自定义加载路由信息
 * @date 2021/11/7 19:37
 */
@Component
public class CustomRouteRepository  implements RouteDefinitionRepository {

    private final static Logger log = LoggerFactory.getLogger(CustomRouteRepository.class);

    private final static ResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver();

    private final static String SERVER_PREFIX = "lb://";

    private Flux<RouteDefinition> routes;

    //路由信息
    private List<RouteDefinition> routeDefinitions;


    @PostConstruct
    private void refreshRoute(){
        log.info("初始化加载路由");
        //初始化路由信息
        getResources((str) ->{
            List<Route> list = JSON.parseArray(str, Route.class);
            this.routeDefinitions = new ArrayList<RouteDefinition>(list.size());
            list.forEach(r ->{
                RouteDefinition convertRouteApi = null;
                try {
                    //构造api
                    convertRouteApi = convertRouteApi(r);
                } catch (Exception e) {
                    log.error(e.getMessage(),e);
                }
                //添加到路由
                routeDefinitions.add(convertRouteApi);
            });

            //执行路由
            routes = Flux.fromIterable(routeDefinitions);

        },"classpath:route.json","file:route.json");


    }



    /**
     * @description: 构造api
     * @param
     * @return
     */
    public RouteDefinition convertRouteApi(Route api) throws URISyntaxException {
        RouteDefinition definition = new RouteDefinition();
        definition.setId(api.getId()+"");
        //路由指向服务id
        String serviceId = api.getServiceId();
        if (StringUtils.isNotBlank(serviceId)){
            //添加服务器地址
            definition.setUri(new URI(SERVER_PREFIX+serviceId));
        } else {
            definition.setUri(new URI(api.getAimUrlPrefix()));
        }

        //新增断言
        List<PredicateDefinition> predicates = new ArrayList<>(1);
        PredicateDefinition p = new PredicateDefinition();
        p.setName("Path");
        Map<String, String> predicateParams = new HashMap<>(1);
        ///该_genkey_前缀是固定的，自定义必须要使用这种规定，其实就是path = “login/**”
        predicateParams.put("_genkey_0",api.getPathPrefix());
        System.out.println(predicateParams);
        p.setArgs(predicateParams);
        predicates.add(p);
        definition.setPredicates(predicates);

        //新增filter
        List<FilterDefinition> filters = new ArrayList<>(1);
        //跳过前缀
        filters.add(createGatewayFilter("StripPrefix",api.getStripPrefix()+""));
        definition.setFilters(filters);
        return definition;
    }


    /**
     * @description: 创建filter过滤
     * @param
     * @return
     */
    private FilterDefinition createGatewayFilter(String filterName,String ...args){
        FilterDefinition filter = new FilterDefinition();
        filter.setName(filterName);
        Map<String, String> filterParams = new HashMap<>(args.length);
        for (int i = 0; i < args.length; i++) {
            //_genkey_也是固定模式，_genkey_0 = 1  会跳过第一层的路由
            // 如果开始路径为anji-open/user/jobuser，那么跳过一层就是 user/jobuser
            filterParams.put("_genkey_"+i,args[i]);
        }
        filter.setArgs(filterParams);
        return filter;
    }


    /**
     * @description: 获取资源
     * @param
     * @return
     */
    private void getResources(Consumer<String> consumer,String ...paths){
        for (String path: paths){
            Resource resources = resourceLoader.getResource(path);
            InputStream inputStream = null;

            try {
                inputStream = resources.getInputStream();
                String routes = IOUtils.toString(inputStream, "utf-8");
                consumer.accept(routes);
                log.info("路由信息: {}",routes);
                return;
            } catch (IOException e) {
                log.error("加载路由文件异常{}",e.getMessage());
                e.printStackTrace();
            } finally {
                FileUtils.close(inputStream);
            }
        }
    }


    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        //如果初始化失败，路由信息没有加载
        if (routes == null){
            //重新加载路由信息
            refreshRoute();
        }
        return routes;
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return null;
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return null;
    }

    public final List<RouteDefinition> getRoutes(){
        return this.routeDefinitions;
    }


    /**
     * @description: 刷新路由
     * @param
     * @return
     */
    public void refresh() {
        refreshRoute();
    }
}
